From c6b465270554f67e8fd3074f7ddb9fc531958613 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Tue, 15 Apr 2008 15:03:40 +0100 Subject: [PATCH] Tasklet bug fixes. Signed-off-by: Keir Fraser --- xen/common/softirq.c | 61 +++++++++++++++++++++++++-------------- xen/include/xen/softirq.h | 3 +- 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/xen/common/softirq.c b/xen/common/softirq.c index 1888d17112..be4728f2e0 100644 --- a/xen/common/softirq.c +++ b/xen/common/softirq.c @@ -61,15 +61,18 @@ void tasklet_schedule(struct tasklet *t) spin_lock_irqsave(&tasklet_lock, flags); - if ( !t->is_scheduled ) + if ( !t->is_dead ) { - list_add(&t->list, &tasklet_list); + if ( !t->is_scheduled && !t->is_running ) + { + BUG_ON(!list_empty(&t->list)); + list_add_tail(&t->list, &tasklet_list); + } t->is_scheduled = 1; + raise_softirq(TASKLET_SOFTIRQ); } spin_unlock_irqrestore(&tasklet_lock, flags); - - raise_softirq(TASKLET_SOFTIRQ); } static void tasklet_action(void) @@ -78,24 +81,38 @@ static void tasklet_action(void) spin_lock_irq(&tasklet_lock); - while ( !list_empty(&tasklet_list) ) + if ( list_empty(&tasklet_list) ) { - t = list_entry(tasklet_list.next, struct tasklet, list); - list_del(&t->list); + spin_unlock_irq(&tasklet_lock); + return; + } + + t = list_entry(tasklet_list.next, struct tasklet, list); + list_del_init(&t->list); - BUG_ON(!t->is_scheduled); - t->is_scheduled = 0; + BUG_ON(t->is_dead || t->is_running || !t->is_scheduled); + t->is_scheduled = 0; + t->is_running = 1; - BUG_ON(t->is_running); - t->is_running = 1; + spin_unlock_irq(&tasklet_lock); + t->func(t->data); + spin_lock_irq(&tasklet_lock); - spin_unlock_irq(&tasklet_lock); - t->func(t->data); - spin_lock_irq(&tasklet_lock); + t->is_running = 0; - t->is_running = 0; + if ( t->is_scheduled ) + { + BUG_ON(t->is_dead || !list_empty(&t->list)); + list_add_tail(&t->list, &tasklet_list); } + /* + * If there is more work to do then reschedule. We don't grab more work + * immediately as we want to allow other softirq work to happen first. + */ + if ( !list_empty(&tasklet_list) ) + raise_softirq(TASKLET_SOFTIRQ); + spin_unlock_irq(&tasklet_lock); } @@ -105,12 +122,14 @@ void tasklet_kill(struct tasklet *t) spin_lock_irqsave(&tasklet_lock, flags); - /* De-schedule the tasklet and prevent it from re-scheduling itself. */ if ( !list_empty(&t->list) ) - list_del(&t->list); - t->is_scheduled = 1; + { + BUG_ON(t->is_dead || t->is_running || !t->is_scheduled); + list_del_init(&t->list); + } + t->is_scheduled = 0; + t->is_dead = 1; - /* Wait for tasklet to complete. */ while ( t->is_running ) { spin_unlock_irqrestore(&tasklet_lock, flags); @@ -118,9 +137,6 @@ void tasklet_kill(struct tasklet *t) spin_lock_irqsave(&tasklet_lock, flags); } - /* Clean up and we're done. */ - t->is_scheduled = 0; - spin_unlock_irqrestore(&tasklet_lock, flags); } @@ -128,6 +144,7 @@ void tasklet_init( struct tasklet *t, void (*func)(unsigned long), unsigned long data) { memset(t, 0, sizeof(*t)); + INIT_LIST_HEAD(&t->list); t->func = func; t->data = data; } diff --git a/xen/include/xen/softirq.h b/xen/include/xen/softirq.h index 4fa7a39b0c..0b59f63b22 100644 --- a/xen/include/xen/softirq.h +++ b/xen/include/xen/softirq.h @@ -62,12 +62,13 @@ struct tasklet struct list_head list; bool_t is_scheduled; bool_t is_running; + bool_t is_dead; void (*func)(unsigned long); unsigned long data; }; #define DECLARE_TASKLET(name, func, data) \ - struct tasklet name = { LIST_HEAD_INIT(name.list), 0, 0, func, data } + struct tasklet name = { LIST_HEAD_INIT(name.list), 0, 0, 0, func, data } void tasklet_schedule(struct tasklet *t); void tasklet_kill(struct tasklet *t); -- 2.30.2